home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
linux
/
tools
/
gtar10.lha
/
buffer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-09
|
31KB
|
1,398 lines
/* Buffer management for tar.
Copyright (C) 1988 Free Software Foundation
This file is part of GNU Tar.
GNU Tar is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU Tar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Tar; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* Buffer management for tar.
*
* Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
*
* @(#) buffer.c 1.28 11/6/87 - gnu
*/
#include <stdio.h>
#include <errno.h>
#include <sys/types.h> /* For non-Berkeley systems */
#include <sys/stat.h>
#include <signal.h>
#ifndef MSDOS
#include <sys/ioctl.h>
#if (!defined(USG) || defined(HAVE_MTIO)) && !defined(amigados)
#include <sys/mtio.h>
#endif
#endif
#ifdef MSDOS
# include <fcntl.h>
#include <process.h>
#else
# ifdef XENIX
# include <sys/inode.h>
# endif
# include <sys/file.h>
#endif
extern int errno;
#include "tar.h"
#include "port.h"
#include "rmt.h"
#include "regex.h"
/* Either stdout or stderr: The thing we write messages (standard msgs, not
errors) to. Stdout unless we're writing a pipe, in which case stderr */
#ifdef amigados
FILE *msg_file = 0;
#else
FILE *msg_file = stdout;
#endif
#define STDIN 0 /* Standard input file descriptor */
#define STDOUT 1 /* Standard output file descriptor */
#define PREAD 0 /* Read file descriptor from pipe() */
#define PWRITE 1 /* Write file descriptor from pipe() */
#ifdef __STDC__
extern void *malloc();
extern void *valloc();
#else
extern char *malloc();
extern char *valloc();
#endif
extern time_t time();
extern char *index(), *strcat();
extern char *strcpy();
/*
* V7 doesn't have a #define for this.
*/
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
#ifndef O_RDWR
#define O_RDWR 2
#endif
#ifndef O_CREAT
#define O_CREAT 0
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define MAGIC_STAT 105 /* Magic status returned by child, if
it can't exec. We hope compress/sh
never return this status! */
void writeerror();
void readerror();
void ck_pipe();
void ck_close();
extern void finish_header();
extern void to_oct();
#ifndef __MSDOS__
/* Obnoxious test to see if dimwit is trying to dump the archive */
dev_t ar_dev;
ino_t ar_ino;
#endif
/*
* The record pointed to by save_rec should not be overlaid
* when reading in a new tape block. Copy it to record_save_area first, and
* change the pointer in *save_rec to point to record_save_area.
* Saved_recno records the record number at the time of the save.
* This is used by annofile() to print the record number of a file's
* header record.
*/
static union record **save_rec;
union record record_save_area;
static long saved_recno;
/*
* PID of child program, if f_compress or remote archive access.
*/
static int childpid = 0;
/*
* Record number of the start of this block of records
*/
long baserec;
/*
* Error recovery stuff
*/
static int r_error_count;
/*
* Have we hit EOF yet?
*/
static int eof;
/* JF we're reading, but we just read the last record and its time to update */
extern time_to_start_writing;
int file_to_switch_to= -1; /* If remote update, close archive, and use
this descriptor to write to */
static int volno = 1; /* JF which volume of a multi-volume tape
we're on */
char *save_name = 0; /* Name of the file we are currently writing */
long save_totsize; /* total size of file we are writing. Only
valid if save_name is non_zero */
long save_sizeleft; /* Where we are in the file we are writing.
Only valid if save_name is non-zero */
int write_archive_to_stdout;
/* Used by fl_read and fl_write to store the real info about saved names */
static char real_s_name[NAMSIZ];
static long real_s_totsize;
static long real_s_sizeleft;
/* Reset the EOF flag (if set), and re-set ar_record, etc */
void
reset_eof()
{
if(eof) {
eof=0;
ar_record=ar_block;
ar_last=ar_block+blocking;
ar_reading=0;
}
}
/*
* Return the location of the next available input or output record.
* Return NULL for EOF. Once we have returned NULL, we just keep returning
* it, to avoid accidentally going on to the next file on the "tape".
*/
union record *
findrec()
{
if (ar_record == ar_last) {
if (eof)
return (union record *)NULL; /* EOF */
flush_archive();
if (ar_record == ar_last) {
eof++;
return (union record *)NULL; /* EOF */
}
}
return ar_record;
}
/*
* Indicate that we have used all records up thru the argument.
* (should the arg have an off-by-1? XXX FIXME)
*/
void
userec(rec)
union record *rec;
{
while(rec >= ar_record)
ar_record++;
/*
* Do NOT flush the archive here. If we do, the same
* argument to userec() could mean the next record (if the
* input block is exactly one record long), which is not what
* is intended.
*/
if (ar_record > ar_last)
abort();
}
/*
* Return a pointer to the end of the current records buffer.
* All the space between findrec() and endofrecs() is available
* for filling with data, or taking data from.
*/
union record *
endofrecs()
{
return ar_last;
}
#if !defined(MSDOS) /* && !defined(amigados) */
/*
* Duplicate a file descriptor into a certain slot.
* Equivalent to BSD "dup2" with error reporting.
*/
void
dupto(from, to, msg)
int from, to;
char *msg;
{
int err;
if (from != to) {
err=close(to);
if(err<0 && errno!=EBADF) {
msg_perror("Cannot close descriptor %d",to);
exit(EX_SYSTEM);
}
err = dup(from);
if (err != to) {
msg_perror("cannot dup %s",msg);
exit(EX_SYSTEM);
}
ck_close(from);
}
}
#endif
#if defined(MSDOS) /* || defined(amigados) */
void
child_open()
{
fprintf(stderr,"DOS %s can't use compressed or remote archives\n",tar);
exit(EX_ARGSBAD);
}
#else
void
child_open()
{
int pipe[2];
int err = 0;
int kidpipe[2];
int kidchildpid;
#define READ 0
#define WRITE 1
ck_pipe(pipe);
#ifdef amigados
childpid=vfork();
#else
childpid=fork();
#endif
if(childpid<0) {
msg_perror("cannot fork");
exit(EX_SYSTEM);
}
if(childpid>0) {
/* We're the parent. Clean up and be happy */
/* This, at least, is easy */
if(ar_reading) {
f_reblock++;
archive=pipe[READ];
ck_close(pipe[WRITE]);
} else {
archive = pipe[WRITE];
ck_close(pipe[READ]);
}
return;
}
/* We're the kid */
if(ar_reading) {
dupto(pipe[WRITE],STDOUT,"(child) pipe to stdout");
ck_close(pipe[READ]);
} else {
dupto(pipe[READ],STDIN,"(child) pipe to stdin");
ck_close(pipe[WRITE]);
}
/* We need a child tar only if
1: we're reading/writing stdin/out (to force reblocking)
2: the file is to be accessed by rmt (compress doesn't know how)
3: the file is not a plain file */
#ifndef amigados
#ifdef NO_REMOTE
if(!(ar_file[0]=='-' && ar_file[1]=='\0') && isfile(ar_file))
#else
if(!(ar_file[0]=='-' && ar_file[1]=='\0') && !_remdev(ar_file) && isfile(ar_file))
#endif
{
#endif /* amigados */
/* We don't need a child tar. Open the archive */
if(ar_reading) {
archive=open(ar_file, O_RDONLY|O_BINARY, 0666);
if(archive<0) {
msg_perror("can't open archive %s",ar_file);
exit(EX_BADARCH);
}
dupto(archive,STDIN,"archive to stdin");
/* close(archive); */
} else {
archive=creat(ar_file,0666);
if(archive<0) {
msg_perror("can't open archive %s",ar_file);
exit(EX_BADARCH);
}
dupto(archive,STDOUT,"archive to stdout");
/* close(archive); */
}
#ifndef amigados
} else {
/* We need a child tar */
ck_pipe(kidpipe);
kidchildpid=fork();
if(kidchildpid<0) {
msg_perror("child can't fork");
exit(EX_SYSTEM);
}
if(kidchildpid>0) {
/* About to exec compress: set up the files */
if(ar_reading) {
dupto(kidpipe[READ],STDIN,"((child)) pipe to stdin");
ck_close(kidpipe[WRITE]);
/* dup2